import os
import xml.sax
import logging
from mod_python import apache, Session

import util


###CONSTANTS

GREENROOM_CONF = "file://" + os.path.dirname(__file__) + "/greenroom.xml"

class ROUTE_TYPE:
	ACTION =	"action"
	VIEW =		"view"

class CONF_TAG:
	GREENROOM =	"greenroom"
	VIEWS = 	"views"
	VIEW =		"view"
	ACTIONS =	"actions"
	ACTION =	"action"
	ROUTE =		"route"

class CONF_ATTR:
	ID =		"id"
	PAGE =		"page"
	CLASS =		"class"
	RESULT =	"result"
	TYPE =		"type"
	RESOURCE =	"resource"


###INITIALIZATION

logging.basicConfig(level=logging.DEBUG,
					format="%(asctime)s %(levelname)s %(message)s",
					filename="/tmp/greenroom.log",
					filemode="w")


class Route:
	def __init__(self, result, resource, type=ROUTE_TYPE.VIEW):
		"""initialize route"""
		self.result = result
		self.resource = resource
		self.type = type


class View:
	def __init__(self, id, page):
		"""initialize view"""
		self.id = id
		self.page = page


class Action:
	def __init__(self, id, clazz):
		"""initialize action"""
		self.id = id
		self.clazz = clazz
		self.route = {}

	def addRoute(self, route):
		"""add route to action"""
		self.route[route.result] = route

	def getRoute(self, result):
		"""get route by result (key)"""
		return self.route[result]


class ConfHandler(xml.sax.handler.ContentHandler):
	def __init__(self):
		"""initialize handler"""
		self.inViews = 0
		self.inActions = 0
		self.inAction = 0
		self.views = {}
		self.actions = {}

	def startElement(self, name, attributes):
		"""handle opening tags"""
		if name == CONF_TAG.VIEWS:
			self.inViews = 1
		if name == CONF_TAG.ACTIONS:
			self.inActions = 1

		if self.inViews:
			if name == CONF_TAG.VIEW:
				id = attributes[CONF_ATTR.ID]
				page = attributes[CONF_ATTR.PAGE]
				v = View(id, page)
				self.views[id] = v

		if self.inActions:
			if name == CONF_TAG.ACTION:
				self.inAction = 1
				id = attributes[CONF_ATTR.ID]
				clazz = attributes[CONF_ATTR.CLASS]
				self.currentAction = Action(id, clazz)
				self.actions[id] = self.currentAction
			if self.inAction:
				if name == CONF_TAG.ROUTE:
					result = attributes[CONF_ATTR.RESULT]
					type = attributes[CONF_ATTR.TYPE]
					resource = attributes[CONF_ATTR.RESOURCE]
					r = Route(result, resource, type)
					self.currentAction.addRoute(r)

	def endElement(self, name):
		"""handle closing tags"""
		if name == CONF_TAG.VIEWS:
			self.inViews = 0
		if name == CONF_TAG.ACTIONS:
			self.inActions = 0
		if name == CONF_TAG.ACTION:
			self.inAction = 0
			del self.currentAction


class DispatcherConf:
	def __init__(self, conf):
		"""parse config and store actions and views"""
		p = xml.sax.make_parser()
		h = ConfHandler()
		p.setContentHandler(h)
		p.parse(conf)
		self.actions = h.actions
		self.views = h.views


DISPATCHER_M = {
	"conf" : DispatcherConf(GREENROOM_CONF),
	"psp" : apache.import_module("mod_python.psp")
}


class Dispatcher:
	"""process action dispatch to resource based on result"""

	def __init__(self, req):
		"""constructor"""
		self.__dict__ = DISPATCHER_M
		req.sess = Session.Session(req)
		self.req = req

	def _processAction(self):
		"""parses action"""
		actionuri = os.path.splitext(self.req.filename)[0]
		path, file = os.path.split(actionuri)
		return self.conf.actions[file]

	def _executeAction(self, action):
		"""create instance and execute action"""
		o = util.Loader().loadObject(action.clazz)
		return o().execute()

	def _processRoute(self, action, result):
		"""decide where to route request"""
		route = action.getRoute(result)
		type = route.type
		if type == ROUTE_TYPE.VIEW:
			view = self.conf.views[route.resource]
		elif type == ROUTE_TYPE.ACTION:
			action = self.conf.actions[route.resource]
			result = self._executeAction(action)
			view = self._processRoute(action, result)
		return view

	def dispatch(self):
		"""delegate work and forward to PSP"""
		action = self._processAction()
		result = self._executeAction(action)
		view = self._processRoute(action, result)
		self.req.sess.save()
		self.req.content_type = "text/html"
		self.req.send_http_header()
		template = self.psp.PSP(self.req,filename=view.page,vars={})
		template.run()
		return apache.OK


def handler(req):
	"""entry point for mod_python, called by PythonHandler"""
	return Dispatcher(req).dispatch()
